﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OpenSearchExplorer
{
    /// <summary>
    /// Interaction logic for QueryResultsPage.xaml
    /// </summary>
    public partial class QueryResultsPage : Page
    {
        Uri query;
        string expectedMimeType;

        public QueryResultsPage(Uri query, string expectedMimeType)
        {
            InitializeComponent();
            this.query = query;
            this.expectedMimeType = expectedMimeType;
        }

         private void runQuery()
        {
            try
            {
                System.Net.WebRequest req = System.Net.WebRequest.Create(query);
                System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse;
                System.IO.StreamReader respStreamReader = new System.IO.StreamReader(resp.GetResponseStream());
                string respString = respStreamReader.ReadToEnd();
                setupRawViewOfQueryResponseContent(respString);
                setupProcessedViewofQueryResponseContent(respString);
                queryLabel.Text = "Query response from " + query.ToString();
            }
            catch (System.Net.WebException ex)
            {
                System.Windows.MessageBox.Show(ex.Message, "Network Problem");
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message, "Problem");
            }
        }

         private void setupProcessedViewofQueryResponseContent(string respString)
         {
             if (expectedMimeType == "text/html")
             {
                 string baseUri = query.GetLeftPart(UriPartial.Authority);
                 string respWithBase = respString.Replace("<head>", "<head>\n<base href=" + baseUri + "\" />");
                 htmlViewer.NavigateToString(respWithBase);
                 htmlTab.Visibility = System.Windows.Visibility.Visible;
                 QueryResponseTabs.SelectedItem = htmlTab;
             }
             else if (expectedMimeType == "application/atom+xml" || expectedMimeType == "application/rss+xml")
             {
                 OpenSearch.IResponse response = new OpenSearch.Response(respString);
                 addText("Title", response.Title);
                 addText("Description", response.Description);
                 addText("Generator", response.Generator);
                 addText("Id", response.Id);
                 addText("Start index", response.StartIndex.ToString());
                 addText("Items per page", response.ItemsPerPage.ToString());
                 addText("Total result count", response.TotalResponseCount.ToString());
                 addAuthors(response.Authors);
                 addQueries(response.Queries);
                 addText("Last updated", response.LastUpdated.ToString());
                 addLinks(response.Links);
                 addItems(response.Items);
                 processedTextTab.Visibility = System.Windows.Visibility.Visible;
                 QueryResponseTabs.SelectedItem = processedTextTab;
             }
         }

         private void addItems(IEnumerable<OpenSearch.IResponseItem> items)
         {
             foreach (OpenSearch.IResponseItem item in items)
             {
                 addText("Item", item.Title);
                 addItemParameter("Summary", item.Summary);
                 if (!string.IsNullOrEmpty(item.Id))
                 {
                     addItemParameter("Id", item.Id);
                 }
                 addItemParameter("Relevance", item.Relevance.ToString());
                 if (item.Published != new DateTime())
                 {
                     addItemParameter("Published", item.Published.ToString());
                 }
                 if (item.LastUpdated != new DateTime())
                 {
                     addItemParameter("Last updated", item.LastUpdated.ToString());
                 }
                 if (!string.IsNullOrEmpty(item.FederationResultSourceId))
                 {
                     addItemParameter("Federation source", item.FederationResultSourceId);
                 }
                 foreach (System.ServiceModel.Syndication.SyndicationPerson author in item.Authors)
                 {
                     addItemParameter("Author", generateFormattedAuthor(author));
                 }
                 addItemParameter("Content", item.Content.MimeType);
                 // addLinks(item.Links);
             }
         }

         private void addItemParameter(string label, string value)
         {
             addText("\t" + label, value);
         }

         private void addLinks(System.Collections.ObjectModel.Collection<System.ServiceModel.Syndication.SyndicationLink> links)
         {
             foreach (System.ServiceModel.Syndication.SyndicationLink link in links)
             {
                 addText("Link", link.Title);
                 addItemParameter("Relation", link.RelationshipType);
                 addItemParameter("MIME type", link.MediaType);
                 addLinkParameter("Uri", link);
             }
         }

         private void addLinkParameter(string label, System.ServiceModel.Syndication.SyndicationLink link)
         {
             queryResponseTextBlock.Inlines.Add(new Bold(new Run("\t" + label + " : ")));
             Run templateRun = new Run(link.Uri.ToString());
             Hyperlink hyperlink = new Hyperlink(templateRun);
             // TODO: make clickable
             queryResponseTextBlock.Inlines.Add(hyperlink);
             queryResponseTextBlock.Inlines.Add(Environment.NewLine);
         }

         private void addQueries(IEnumerable<string> queries)
         {
             foreach (string query in queries)
             {
                 addText("Query", query);
             }
         }

         private void addAuthors(System.Collections.ObjectModel.Collection<System.ServiceModel.Syndication.SyndicationPerson> authors)
         {
             foreach (System.ServiceModel.Syndication.SyndicationPerson author in authors)
             {
                 addText("Author", generateFormattedAuthor(author));
             }
         }

         private static string generateFormattedAuthor(System.ServiceModel.Syndication.SyndicationPerson author)
         {
             string formattedAuthor = "";
             if ((!string.IsNullOrEmpty(author.Name)) && (!string.IsNullOrEmpty(author.Email)))
             {
                 formattedAuthor = author.Name + " (" + author.Email + ")";
             }
             else if ((!string.IsNullOrEmpty(author.Name)) && (!string.IsNullOrEmpty(author.Uri)))
             {
                 formattedAuthor = author.Name + " (" + author.Uri + ")";
             }
             else if (!string.IsNullOrEmpty(author.Name))
             {
                 formattedAuthor = author.Name;
             }
             return formattedAuthor;
         }

         private void addText(string label, string value)
         {
             queryResponseTextBlock.Inlines.Add(new Bold(new Run(label + " : ")));
             queryResponseTextBlock.Inlines.Add(new Run(value));
             queryResponseTextBlock.Inlines.Add(Environment.NewLine);
         }

         private void setupRawViewOfQueryResponseContent(string respString)
         {
             queryResponseRawView.Document.Text = respString;
             if ((expectedMimeType == "text/html") || (expectedMimeType.Contains("xml")))
             {
                 enableXmlFoldingForRawView();
             }
             else if (expectedMimeType == "text/plain")
             {
                 // nothing
             }

             queryResponseRawView.IsReadOnly = true;
             QueryResponseTabs.SelectedItem = rawResponseViewTab;
         }

         private void enableXmlFoldingForRawView()
         {
             ICSharpCode.AvalonEdit.Folding.FoldingManager foldingManager = ICSharpCode.AvalonEdit.Folding.FoldingManager.Install(queryResponseRawView.TextArea);
             ICSharpCode.AvalonEdit.Folding.XmlFoldingStrategy foldingStrategy = new ICSharpCode.AvalonEdit.Folding.XmlFoldingStrategy();
             foldingStrategy.UpdateFoldings(foldingManager, queryResponseRawView.Document);
         }

        private void QueryResultsLabel_Loaded(object sender, RoutedEventArgs e)
        {
            runQuery();
        }

        private void SaveAsButton_Click(object sender, RoutedEventArgs e)
        {
            if (QueryResponseTabs.SelectedItem == rawResponseViewTab)
            {
                Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog()
                {
                    Filter = "Text Files(*.txt)|*.txt|All(*.*)|*"
                };
                if (dialog.ShowDialog() == true)
                {
                    queryResponseRawView.Save(dialog.FileName);
                }
            }
            else if (QueryResponseTabs.SelectedItem == processedTextTab)
            {
                Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog()
                {
                    Filter = "Text Files(*.txt)|*.txt|All(*.*)|*"
                };
                if (dialog.ShowDialog() == true)
                {
                    StringBuilder s = new StringBuilder();
                    BuildStringFromInlines(s, queryResponseTextBlock.Inlines);
                    System.IO.File.WriteAllText(dialog.FileName, s.ToString()); 
                }
            }
            else if (QueryResponseTabs.SelectedItem == htmlTab)
            {
                Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog()
                {
                    Filter = "HTML Files(*.html)|*.html|All(*.*)|*"
                };
                if (dialog.ShowDialog() == true)
                {
                    dynamic doc = htmlViewer.Document;
                    System.IO.File.WriteAllText(dialog.FileName, doc.documentElement.InnerHtml); 
                }
            }
        }

        private void BuildStringFromInlines(StringBuilder s, InlineCollection inlines)
        {
            foreach (var line in inlines)
            {
                if (line is LineBreak)
                {
                    s.AppendLine();
                }
                else if (line is Run)
                {
                    Run run = line as Run;
                    s.Append(run.Text);
                }
                else if (line is Span)
                {
                    Span span = line as Span;
                    BuildStringFromInlines(s, span.Inlines);
                }
                else
                {
                }
            }
        }
    }
}
